package com.yjzx.util.service.pay.service.impl;

import com.yjzx.util.service.pay.constants.BaseConstant;
import com.yjzx.util.service.pay.enums.ClientEnum;
import com.yjzx.util.service.pay.service.PayService;
import com.yjzx.util.service.pay.strategy.OrderInterface;
import com.yjzx.util.service.pay.strategy.PayStrategy;
import com.yjzx.util.service.pay.strategy.PaySuccessParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author yjzx
 * @Description 支付上下文引用支付策略； 模板类
 * @create 2022-12-28 22:46
 */
@Service
@Slf4j
public class PayServiceImpl implements PayService {
    /**
     * 注入支付策略，将存在的所以策略注入此集合
     */
    private final Map<String, PayStrategy> payStrategies;

    @Autowired
    public PayServiceImpl(List<PayStrategy> payStrategies) {
        this.payStrategies = payStrategies.stream().collect(Collectors.toMap(PayStrategy::getName, x -> x));
    }
    class OrderInfo implements OrderInterface {

        @Override
        public String getOrderInfoId() {
            return null;
        }
        public boolean isPay(){
            return false;
        }

        @Override
        public ClientEnum getClientEnum() {
            return null;
        }

        @Override
        public String getOutTradeNo() {
            return null;
        }

        @Override
        public BigDecimal getPrice() {
            return null;
        }

        @Override
        public String getOrderName() {
            return null;
        }

        @Override
        public String getDesc() {
            return null;
        }

        @Override
        public Date getExpireTime() {
            return null;
        }
    }

    @Override
    public String getMiniOpenId(String type,String id) {
        //2、生成支付页
        for (PayStrategy strategy : payStrategies.values()) {
            if (strategy.supports(type)) {
                //获取收银台页面
                return strategy.getMiniOpenId(id);
            }
        }
        throw new IllegalArgumentException("不支持的支付类型");
    }

    /**
     * 生成收银台页面
     *
     * @param type    支付类型
     * @param orderId 订单id
     * @return
     */
    @Override
    public Object payPage(String type, String orderId) {
        //1、查询数据库订单
        OrderInterface anInterface = new OrderInfo();

        //2、生成支付页
        for (PayStrategy strategy : payStrategies.values()) {
            if (strategy.supports(type)) {
                //获取收银台页面
                return strategy.cashierPage(anInterface);
            }
        }
        //3、如果以上都不支持，打印错误
        return BaseConstant.NOT_PAYMENT_METHOD;
    }

    /**
     * 处理支付通知
     *
     * @param request 支付情况请求
     * @param body    请求参数
     * @return
     */
    @Override
    public Object processNotify(HttpServletRequest request, Map<String, String> params, Map<String, String> headers, String body, String payType, ClientEnum clientEnum) {
        Object result = BaseConstant.NOT_PAYMENT_METHOD;

        PaySuccessParam data = null;

        //2、验证签名
        for (PayStrategy strategy : payStrategies.values()) {
            if (strategy.supports(payType)) {
                //签名校验
                boolean checkSign = strategy.checkSign(request, body,clientEnum);
                if (!checkSign) {
                    log.error("签名验证失败，疑似攻击请求");
                    //验签失败返回
                    return strategy.signError();
                } else {
                    log.info("签名验证成功，提取通知数据");
                    //验签成功处理数据
                    data = strategy.process(request, body);
                    //验签成功返回
                    result = strategy.signOk();
                }
            }
        }

        //3、通用的后续处理算法；处理订单数据
        processOrder(data);
        return result;
    }

    /**
     * 订单退单
     * @param orderId 订单id
     * @param payType
     * @param clientEnum
     * @return
     */
    @Override
    public boolean payChargebacks(String orderId, String payType, ClientEnum clientEnum) {
        for (PayStrategy value : payStrategies.values()) {
            if (value.getName().equals(payType)) {
                return value.payChargebacks(orderId,clientEnum);
            }
        }
        return false;
    }

    @Override
    public String payQuery(String orderId, String payType, ClientEnum clientEnum) {
        //数据库查询订单支付状态
        OrderInfo info = new OrderInfo();

        if (!info.isPay()){
            for (PayStrategy value : payStrategies.values()) {
                if (value.getName().equals(payType)) {
                    value.payQuery(orderId,clientEnum);
                }
            }
            throw new IllegalArgumentException("不支持的支付类型");
        }else {
            return info.getOrderInfoId();
        }

    }


    /**
     * 处理订单数据
     *
     * @param data 请求参数
     */
    private void processOrder(PaySuccessParam data) {
        //TODO 把支付成功信息等保存数据库，并修改订单状态，通知库存系统等...
        log.info("订单支付成功，状态修改完成，已通知库存系统，详细数据：{}", data);
    }

    /**
     * 判断通知类型
     *
     * @param request 请求参数
     * @return
     */
    private String getNotifyType(HttpServletRequest request) {
        //判断是否存在微信的支付请求头
        String header = request.getHeader("wechatpay-serial");
        if (StringUtils.hasText(header)) {
            return "weixin";
        }
        //如果此请求体中存在此字段，是阿里支付
        String app_id = request.getParameter("app_id");
        if (StringUtils.hasText(app_id)) {
            return "alipay";
        }


        return "unknown";
    }


}
